package com.ruoyi.common.utils;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

@Component
@Slf4j
public class FieldUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * @description: 通过实体类获取对应的mapper类
     * @param entityClass
     * @return: java.lang.Class<?>
     * @author: "蔡裕鑫"
     * @time: 2024/1/19 10:29
     */
    private static Class<?> getMapperClass(Class<?> entityClass){
        Class<?> mapperClass = null;
        //根据实体类获取对应mapper类名
        int fourthDotIndex = findFourthDotIndex(entityClass.getName(), 4);
        StringBuilder builder = new StringBuilder(entityClass.getName().replace("VO", ""));
        String entityName = builder.replace(fourthDotIndex ,fourthDotIndex + 7 ,".service.mapper").toString();
        String mapperClassName =  entityName.replace("Entity" ,"Mapper");
        //通过mapper类名获取mapper类
        try {
            mapperClass = Class.forName(mapperClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return mapperClass;
    }

    /**
     * @description:
     * @param inputEntity 输入实体类
     * @param entityId 输入实体类对应的主键的字段名
     * @param targetStr 实体类中想进行查重的目标字段名 以下注释中对该变成称 目标字段名
     * @param bInOrUpdate 判断当前是被应用于新增接口还是修改接口 true为新增 false为修改
     * @return: java.lang.Boolean
     * @author: "蔡裕鑫"
     * @time: 2024/1/19 11:44
     */
    //TODO:将targetStr拓展为 ...targetStr  以及新加条件筛选
    public static <T> boolean duplicateCheck(T inputEntity ,String entityId ,String targetStr ,Boolean bInOrUpdate){
        String targetValue = null;
        String inputIdValue = null;
        try {
            //获取输入实体类对应的mapper类
            Class<?> mapperClass = getMapperClass(inputEntity.getClass());
            // 获取Mapper层对应的Bean实例
            Object mapper = applicationContext.getBean(mapperClass);


            //获取输入实体类id字段名并设置为可访问
            Field inputId = inputEntity.getClass().getDeclaredField(entityId);
            inputId.setAccessible(true);
            if (!StrUtil.isEmptyIfStr(inputId) && bInOrUpdate == false){
                inputIdValue = inputId.get(inputEntity).toString();//输入实体类id值
            }
            System.out.println(inputIdValue);
            //获取目标字段名并设置为可访问
            Field targetField = inputEntity.getClass().getDeclaredField(targetStr);
            targetField.setAccessible(true);
            String inputTargetValue = targetField.get(inputEntity).toString();//目标字段值

            //获取嘉善字段名并设置为可访问
            Field delFlagField = inputEntity.getClass().getDeclaredField("delFlag");
            delFlagField.setAccessible(true);

            //修改分支判断
            if (!StringUtil.isEmpty(inputIdValue)){
                /** oldEntity为数据库查出来的实体类数据 以下称为数据库实体类 **/
                T oldEntity = ((BaseMapper<T>) mapper).selectById(inputIdValue);
                //判断数据库实体类是否为空 不为空则通过反射获取目标字段名
                if (oldEntity != null){
                    //获取在数据库中的目标字段并设置为可访问
                    Field sourceField = oldEntity.getClass().getDeclaredField(targetStr);
                    sourceField.setAccessible(true);
                    targetValue = sourceField.get(oldEntity).toString();//从数据库中查出来的目标字段值
                }
            }

            String targetSnakeCase = lowToSnakeCase(targetStr);
            //判断是否重复 且 若修改操作时允许输入的名称与原名称相同
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(targetSnakeCase ,inputTargetValue).eq("del_flag" ,1);
            T oldData = ((BaseMapper<T>) mapper).selectOne(queryWrapper);
            if (!(StrUtil.isEmptyIfStr(oldData)) && !inputTargetValue.equals(targetValue)){
                return true;
            }

        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return false;
    }

    //实体类对象判空
    public static <T> boolean fieldIsEmpty(String fields ,T entity){
        //拆分目标字段进一个字符串数组内
        String[] fieldArr = fields.split(",");
        Class<?> entityClass = entity.getClass();
        try {
            for (String field : fieldArr){
                //获得字段名
                Field declaredField = entityClass.getDeclaredField(field);
                //设置可读
                declaredField.setAccessible(true);
                //获得字段值
                Object fieldValue = declaredField.get(entity);

                if (fieldValue != null){
                    String fieldValueStr = fieldValue.toString();
                    if (StrUtil.isEmpty(fieldValueStr)){
                        return true;
                    }
                } else {
                    return true;
                }
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return false;
    }

    /**
      *methood: 对实体类的.进行查询用于重新拼接mapper类名
      *auth: cyx
      *time: 2024/6/4 17:27
    **/
    public static int findFourthDotIndex(String str ,int targetPoint) {
        int dotCount = 0;
        int dotIndex = -1;

        while (dotCount < targetPoint && (dotIndex = str.indexOf('.', dotIndex + 1)) != -1) {
            dotCount++;
        }

        return dotCount == targetPoint ? dotIndex : -1;
    }

    /**
      *methood: 将小驼峰转为下划线
      *auth: cyx
      *time: 2024/6/4 18:08
    **/
    public static String lowToSnakeCase(String source){
        String resultStr = "";
        char[] charArray = source.toCharArray();
        for (int i = 0 ;i < charArray.length ;i ++){
            if (Character.isUpperCase(charArray[i])){
                resultStr = resultStr + "_" + Character.toLowerCase(charArray[i]);
            } else {
                resultStr += charArray[i];
            }
        }
        return resultStr;
    }

    public static boolean checkNumber(String str){
        try {
            Double.parseDouble(str);
            log.info("检查" + str + "为数字，返回True");
            return true;
        } catch (NumberFormatException e) {
            log.info("检查" + str + "为非数字，返回False");
            return false;
        }
    }
}
